/*******************************************************************************
 * Copyright (c) 2011, 2016 Eurotech and/or its affiliates
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Eurotech
 *******************************************************************************/
package org.eclipse.kura.net.modem;

import org.eclipse.kura.net.IPAddress;
import org.eclipse.kura.net.NetConfig;

/**
 * Modem configuration representation
 *
 */
public class ModemConfig implements NetConfig {

    /**
     * Configuration for a cellular modem.
     */
    public static enum PdpType {
        IP, PPP, IPv6, UNKNOWN
    };

    public static enum AuthType {
        NONE, AUTO, PAP, CHAP
    };

    private boolean m_enabled = false;
    private String m_dialString = "";
    private int m_pppNumber = 0;
    private int m_profileID = 0;
    private PdpType m_pdpType = PdpType.IP;
    private AuthType m_authType = AuthType.NONE;
    private String m_apn = "";
    private String m_username = "";
    private String m_password = "";
    private boolean m_persist = false;
    private int m_maxFail = 0;
    private int m_idle = 0;
    private String m_activeFilter = "";
    private int m_lcpEchoInterval = 0;
    private int m_lcpEchoFailure = 0;
    private IPAddress m_ipAddress = null;
    private int m_dataCompression = 0;			// FIXME: change to enum?
    private int m_headerCompression = 0;		// FIXME: change to enum?
    private boolean m_gpsEnabled = false;
    private int m_resetTimeout = 0;

    /**
     * Empty constructor
     */
    public ModemConfig() {
    }

    /**
     * PDP config constructor
     *
     * @param apn
     *            - access point name as {@link String}
     * @param ipAddress
     *            - IP address as {@link String}
     * @param profileID
     *            - PDP profile ID as {@link int}
     * @param pdpType
     *            - PDP type as {@link PdpType}
     * @param dataCompression
     *            - PDP data compression as {@link int}
     * @param headerCompresion
     *            - PDP header compression as {@link int}
     */
    public ModemConfig(int profileID, PdpType pdpType, String apn, IPAddress ipAddress, int dataCompression,
            int headerCompresion) {

        this.m_profileID = profileID;
        this.m_pdpType = pdpType;
        this.m_apn = apn;
        this.m_ipAddress = ipAddress;
        this.m_dataCompression = dataCompression;
        this.m_headerCompression = headerCompresion;
    }

    /**
     * Reports whether it is enabled.
     *
     * @return is enabled as {@link boolean}
     */
    public boolean isEnabled() {
        return this.m_enabled;
    }

    /**
     * Sets the enabled setting.
     *
     * @param enabled
     *            - enabled status as {@link boolean}
     */
    public void setEnabled(boolean enabled) {
        this.m_enabled = enabled;
    }

    /**
     * Gets the dial string.
     *
     * @return dial string as {@link String}
     */
    public String getDialString() {
        return this.m_dialString;
    }

    /**
     * Sets the dial string.
     *
     * @param dialString
     *            - dial string as {@link String}
     */
    public void setDialString(String dialString) {
        this.m_dialString = dialString;
    }

    /**
     * Reports authentication type.
     *
     * @return authentication type as {@link AuthType}
     */
    public AuthType getAuthType() {
        return this.m_authType;
    }

    /**
     * Sets authentication type.
     *
     * @param authType
     *            - authentication type as {@link AuthType}
     */
    public void setAuthType(AuthType authType) {
        this.m_authType = authType;
    }

    /**
     * Reports user name.
     *
     * @return user name as {@link String}
     */
    public String getUsername() {
        return this.m_username;
    }

    /**
     * Sets user name.
     *
     * @param username
     *            - user name as {@link String}
     */
    public void setUsername(String username) {
        this.m_username = username;
    }

    /**
     * Reports password.
     *
     * @return password as {@link String}
     */
    public String getPassword() {
        return this.m_password;
    }

    /**
     * Sets password.
     *
     * @param password
     *            - password as {@link String}
     */
    public void setPassword(String password) {
        this.m_password = password;
    }

    /**
     * Reports if pppd is instructed to exit after a connection is terminated.
     *
     * @return 'persist' flag {@link boolean}
     */
    public boolean isPersist() {
        return this.m_persist;
    }

    /**
     * Sets 'persist' flag to instruct pppd if it needs to exit after a connection is terminated.
     *
     * @param persist
     *            as {@link boolean}
     */
    public void setPersist(boolean persist) {
        this.m_persist = persist;
    }

    /**
     * Reports maximum number of failed connection attempts.
     *
     * @return maximum number of failed connection attempts as {@link int}
     */
    public int getMaxFail() {
        return this.m_maxFail;
    }

    /**
     * Sets maximum number of failed connection attempts
     *
     * @param maxFail
     *            - maximum number of failed connection attempts as {@link int}
     */
    public void setMaxFail(int maxFail) {
        this.m_maxFail = maxFail;
    }

    /**
     * Reports value of the 'idle' option.
     * The 'idle' option specifies that pppd should disconnect if the link is idle for n seconds.
     *
     * @return value of the 'idle' option as {@link int}
     */
    public int getIdle() {
        return this.m_idle;
    }

    /**
     * Sets value of the 'idle' option.
     * The 'idle' option specifies that pppd should disconnect if the link is idle for n seconds.
     *
     * @param idle
     */
    public void setIdle(int idle) {
        this.m_idle = idle;
    }

    /**
     * Reports the value of the 'active-filter' option that specifies a packet filter to be
     * applied to data packets to determine which packets are to be regarded as link activity.
     *
     * @return value of the 'active-filter' option as {@link String}
     */
    public String getActiveFilter() {
        return this.m_activeFilter;
    }

    /**
     * Sets the value of the 'active-filter' option that specifies a packet filter to be
     * applied to data packets to determine which packets are to be regarded as link activity.
     *
     * @param activeFilter
     *            - active filter as {@link String}
     */
    public void setActiveFilter(String activeFilter) {
        this.m_activeFilter = activeFilter;
    }

    /**
     * Reports LCP echo interval
     *
     * @return LCP echo interval (in sec) as {@link int}
     */
    public int getLcpEchoInterval() {
        return this.m_lcpEchoInterval;
    }

    /**
     * Sets LCP echo interval
     *
     * @param lcpEchoInterval
     *            - LCP Echo interval as {@link int}
     */
    public void setLcpEchoInterval(int lcpEchoInterval) {
        this.m_lcpEchoInterval = lcpEchoInterval;
    }

    /**
     * Reports number of failed LCP echo requests
     *
     * @return number of failed LCP echo requests as {@link int}
     */
    public int getLcpEchoFailure() {
        return this.m_lcpEchoFailure;
    }

    /**
     * Sets number of failed LCP echo requests
     * (unacknowledged LCP echo requests to be sent for pppd to presume the peer to be dead)
     *
     * @param lcpEchoFailure
     */
    public void setLcpEchoFailure(int lcpEchoFailure) {
        this.m_lcpEchoFailure = lcpEchoFailure;
    }

    /**
     * Reports PPP number (i.e. '0' for ppp0).
     *
     * @return PPP number as {@link int}
     */
    public int getPppNumber() {
        return this.m_pppNumber;
    }

    /**
     * Sets PPP number (i.e. '0' for ppp0).
     *
     * @param pppNumber
     *            - PPP number as {@link int}
     */
    public void setPppNumber(int pppNumber) {
        this.m_pppNumber = pppNumber;
    }

    /**
     * Reports PDP profile ID.
     *
     * @return PDP profile ID as {@link int}
     */
    public int getProfileID() {
        return this.m_profileID;
    }

    /**
     * Sets PDP profile ID.
     *
     * @param id
     *            - PDP profile ID as {@link int}
     */
    public void setProfileID(int id) {
        this.m_profileID = id;
    }

    /**
     * Reports PDP type.
     *
     * @return PDP type as {@link PdpType}
     */
    public PdpType getPdpType() {
        return this.m_pdpType;
    }

    /**
     * Sets PDP type.
     *
     * @param pdpType
     *            - PDP type as {@link PdpType}
     */
    public void setPdpType(PdpType pdpType) {
        this.m_pdpType = pdpType;
    }

    /**
     * Reports access point name.
     *
     * @return access point name as {@link String}
     */
    public String getApn() {
        return this.m_apn;
    }

    /**
     * Sets access point name.
     *
     * @param apn
     *            - access point name as {@link String}
     */
    public void setApn(String apn) {
        this.m_apn = apn;
    }

    /**
     * Reports PDP IP address.
     *
     * @return IP address as {@link IPAddress}
     */
    public IPAddress getIpAddress() {
        return this.m_ipAddress;
    }

    /**
     * Sets PDP IP address.
     *
     * @param address
     *            - IP address as {@link IPAddress}
     */
    public void setIpAddress(IPAddress address) {
        this.m_ipAddress = address;
    }

    /**
     * Reports a value of numeric parameter that supports PDP data compression.
     *
     * @return PDP data compression as {@link int}
     */
    public int getDataCompression() {
        return this.m_dataCompression;
    }

    /**
     * Sets a value of numeric parameter that supports PDP data compression.
     *
     * @param dataCompression
     *            - PDP data compression as {@link int}
     */
    public void setDataCompression(int dataCompression) {
        this.m_dataCompression = dataCompression;
    }

    /**
     * Reports a value of numeric parameter that supports PDP header compression.
     *
     * @return PDP header compression as {@link int}
     */
    public int getHeaderCompression() {
        return this.m_headerCompression;
    }

    /**
     * Sets a value of numeric parameter that supports PDP header compression.
     *
     * @param headerCompression
     *            headerCompression PDP header compression as {@link int}
     */
    public void setHeaderCompression(int headerCompression) {
        this.m_headerCompression = headerCompression;
    }

    /**
     * Reports if PDP data compression is enabled.
     *
     * @return {@link boolean}
     */
    public boolean isDataCompression() {
        return this.m_dataCompression == 0 ? false : true;
    }

    /**
     * Reports if PDP header compression is enabled.
     *
     * @return {@link boolean}
     */
    public boolean isHeaderCompression() {
        return this.m_headerCompression == 0 ? false : true;
    }

    public boolean isGpsEnabled() {
        return this.m_gpsEnabled;
    }

    public int getResetTimeout() {
        return this.m_resetTimeout;
    }

    public void setResetTimeout(int tout) {
        this.m_resetTimeout = tout;
    }

    public void setGpsEnabled(boolean gpsEnabled) {
        this.m_gpsEnabled = gpsEnabled;
    }

    @Override
    public int hashCode() {
        final int prime = 59;
        int result = super.hashCode();

        result = prime * result + this.m_profileID;
        result = prime * result + (this.m_pdpType == null ? 0 : this.m_pdpType.hashCode());
        result = prime * result + (this.m_authType == null ? 0 : this.m_authType.hashCode());
        result = prime * result + (this.m_apn == null ? 0 : this.m_apn.hashCode());
        result = prime * result + (this.m_username == null ? 0 : this.m_username.hashCode());
        result = prime * result + (this.m_password == null ? 0 : this.m_password.hashCode());
        result = prime * result + (this.m_ipAddress == null ? 0 : this.m_ipAddress.hashCode());
        result = prime * result + this.m_pppNumber;
        result = prime * result + this.m_maxFail;
        result = prime * result + this.m_resetTimeout;
        result = prime * result + this.m_idle;
        result = prime * result + (this.m_activeFilter == null ? 0 : this.m_activeFilter.hashCode());
        result = prime * result + this.m_lcpEchoFailure;
        result = prime * result + this.m_lcpEchoInterval;
        result = prime * result + this.m_dataCompression;
        result = prime * result + this.m_headerCompression;
        result = prime * result + (this.m_persist ? 1 : 0);
        result = prime * result + (this.m_gpsEnabled ? 1 : 0);

        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof ModemConfig)) {
            return false;
        }

        ModemConfig otherConfig = (ModemConfig) obj;

        if (this.m_enabled != otherConfig.isEnabled()) {
            return false;
        }

        if (this.m_pppNumber != otherConfig.getPppNumber()) {
            return false;
        }

        if (this.m_persist != otherConfig.isPersist()) {
            return false;
        }

        if (this.m_maxFail != otherConfig.getMaxFail()) {
            return false;
        }

        if (this.m_resetTimeout != otherConfig.getResetTimeout()) {
            return false;
        }

        if (this.m_idle != otherConfig.getIdle()) {
            return false;
        }

        if (this.m_lcpEchoInterval != otherConfig.getLcpEchoInterval()) {
            return false;
        }

        if (this.m_lcpEchoFailure != otherConfig.getLcpEchoFailure()) {
            return false;
        }

        if (this.m_profileID != otherConfig.getProfileID()) {
            return false;
        }

        if (this.m_pdpType != otherConfig.getPdpType()) {
            return false;
        }

        if (this.m_authType != otherConfig.getAuthType()) {
            return false;
        }

        if (this.m_dataCompression != otherConfig.getDataCompression()) {
            return false;
        }

        if (this.m_headerCompression != otherConfig.getHeaderCompression()) {
            return false;
        }

        if (this.m_gpsEnabled != otherConfig.isGpsEnabled()) {
            return false;
        }

        if (this.m_dialString != null) {
            if (!this.m_dialString.equals(otherConfig.getDialString())) {
                return false;
            }
        } else {
            if (otherConfig.getDialString() != null) {
                return false;
            }
        }
        if (this.m_apn != null) {
            if (!this.m_apn.equals(otherConfig.getApn())) {
                return false;
            }
        } else {
            if (otherConfig.getApn() != null) {
                return false;
            }
        }

        if (this.m_username != null && this.m_username.length() > 0) {
            if (!this.m_username.equals(otherConfig.getUsername())) {
                return false;
            }
        } else {
            if (otherConfig.getUsername() != null && otherConfig.getUsername().length() > 0) {
                return false;
            }
        }

        if (this.m_password != null && this.m_password.length() > 0) {
            if (!this.m_password.equals(otherConfig.getPassword())) {
                return false;
            }
        } else {
            if (otherConfig.getPassword() != null && otherConfig.getPassword().length() > 0) {
                return false;
            }
        }

        if (this.m_activeFilter != null && this.m_activeFilter.length() > 0) {
            if (!this.m_activeFilter.equals(otherConfig.getActiveFilter())) {
                return false;
            }
        } else {
            if (otherConfig.getActiveFilter() != null && otherConfig.getActiveFilter().length() > 0) {
                return false;
            }
        }

        if (this.m_ipAddress != null) {
            if (!this.m_ipAddress.equals(otherConfig)) {
                return false;
            }
        } else {
            if (otherConfig.getIpAddress() != null) {
                return false;
            }
        }

        return true;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append(super.toString());

        sb.append("ModemConfig - ");

        sb.append("Enabled: ").append(this.m_enabled);
        sb.append(" - PPP Number: ").append(this.m_pppNumber);
        sb.append(" - Dial String: ").append(this.m_dialString);
        // sb.append(" - Provider: ").append(m_provider);
        sb.append(" - Profile ID: ").append(this.m_profileID);
        sb.append(" - PDP Type: ").append(this.m_pdpType);
        sb.append(" - Auth Type: ").append(this.m_authType);
        sb.append(" - APN: ").append(this.m_apn);
        sb.append(" - Username: ").append(this.m_username);
        sb.append(" - Password: ").append(this.m_password);
        sb.append(" - IP Address: ").append(this.m_ipAddress == null ? "null" : this.m_ipAddress.getHostAddress());
        sb.append(" - Data Compression: ").append(this.m_dataCompression);
        sb.append(" - Header Compression: ").append(this.m_headerCompression);

        return sb.toString();
    }

    @Override
    public boolean isValid() {
        if (this.m_pppNumber < 0) {
            return false;
        }

        return true;
    }
}
